/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.ts.manager.impl;

import java.util.*;
import java.util.stream.Collectors;

import com.xy.biz.ts.dao.*;
import com.xy.biz.ts.domain.bo.*;
import com.xy.biz.ts.domain.converter.*;
import com.xy.biz.ts.domain.po.*;
import com.xy.biz.ts.domain.query.*;
import com.xy.biz.uc.client.UserClient;
import com.xy.biz.uc.domain.dto.UserDTO;
import com.xy.biz.uc.domain.req.ListUserGroupByIdsRequest;
import com.xy.lang.util.ResultUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xy.biz.ts.manager.TrainManager;
import org.springframework.util.CollectionUtils;

import static java.util.stream.Collectors.toList;

/**
 *
 *
 * @author wwj
 * @date 2021-4-1
 */
@Service
public class TrainManagerImpl implements TrainManager {

    @Autowired
    private TrainDao trainDao;
    @Autowired
    private TrainFlowHandleDao trainFlowHandleDao;
    @Autowired
    private TrainUserDao trainUserDao;
    @Autowired
    private TrainUserGroupDao trainUserGroupDao;
    @Autowired
    private TrainDocumentRelDao trainDocumentRelDao;
    @Autowired
    private UserClient userClient;
    @Autowired
    private LearnRecordDao learnRecordDao;
    @Autowired
    private PracticeRecordDao practiceRecordDao;
    @Autowired
    private ExaminationRecordDao examinationRecordDao;

    @Override
    public TrainBO saveTrain(TrainBO trainBO) {
        TrainPO trainPO = TrainConverter.toPO(trainBO);
        int row = trainDao.saveTrain(trainPO);
        if (row > 0) {
            List<TrainFlowHandleBO> trainFlowHandleBOList = trainBO.getTrainFlowHandleList();
            if (!CollectionUtils.isEmpty(trainFlowHandleBOList)) {
                List<TrainFlowHandlePO> trainFlowHandlePOS = TrainFlowHandleConverter.toPO(trainFlowHandleBOList);
                trainFlowHandleDao.saveAllTrainFlowHandle(trainFlowHandlePOS);
            }
        }

        return TrainConverter.fromPO(trainPO);
    }

    @Override
    public int saveAllTrain(Collection<TrainBO> collection) {
        return trainDao.saveAllTrain(TrainConverter.toPO(collection));
    }

    @Override
    public int updateTrain(TrainBO trainBO) {
        return trainDao.updateTrain(TrainConverter.toPO(trainBO));
    }

    @Override
    public int changeStatus(Map<Integer, Set<Long>> collection) {
        return trainDao.changeStatus(collection);
    }

    /**
     * 更新考核状态
     *
     * @param trainId
     */
    @Override
    public int startExamination(Long trainId) {
        return trainDao.startExamination(trainId);
    }

    @Override
    public int deleteTrain(Long trainId) {
        return trainDao.deleteTrain(trainId);
    }

    @Override
    public TrainBO getTrain(Long trainId) {
        return TrainConverter.fromPO(trainDao.getTrain(trainId));
    }

    @Override
    public List<TrainBO> listTrainById(Collection<Long> collection) {
        if (CollectionUtils.isEmpty(collection)) {
            return Collections.emptyList();
        }
        return TrainConverter.fromPO(trainDao.listTrainById(collection));
    }

    @Override
    public List<TrainBO> listTrain(TrainQuery query) {
        List<TrainBO> trainBOS = TrainConverter.fromPO(trainDao.listTrain(query));
        buildTrainBO(trainBOS, query.isWithUserGroup(), query.isWithUser(), query.isWithLearnRecord(), query.isWithPracticeRecord(), query.isWithExaminationRecord());
        return trainBOS;
    }

    /**
     * 查找多个
     *
     * @param query 查找条件
     */
    @Override
    public List<TrainBO> listTrainId(TrainQuery query) {
        return TrainConverter.fromPO(trainDao.listTrainId(query));
    }

    private void buildTrainBO(List<TrainBO> trainBOList, boolean isWithUserGroup, boolean isWithUser, boolean isWithLearnRecord, boolean isWithPracticeRecord, boolean isWithExaminationRecord) {
        Set<Long> trainIdList = trainBOList.stream().map(TrainBO::getTrainId).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(trainIdList)) {
            return;
        }
        List<TrainUserBO> trainUserBOS = TrainUserConverter.fromPO(
                trainUserDao.listTrainUser(TrainUserQuery.max().trainIdS(trainIdList).build()));

        Map<Long, List<LearnRecordBO>> learnMap = new HashMap<>();
        if (isWithLearnRecord) {
            learnMap.putAll(LearnRecordConverter.fromPO(
                            learnRecordDao.listLearnRecord(
                                    LearnRecordQuery.max().trainIds(trainIdList).build()))
                    .stream().collect(Collectors.groupingBy(LearnRecordBO::getLearnUserId)));
        }
        Map<Long, List<PracticeRecordBO>> practiceMap = new HashMap<>();
        if (isWithPracticeRecord) {
            practiceMap.putAll(PracticeRecordConverter.fromPO(
                            practiceRecordDao.listPracticeRecord(
                                    PracticeRecordQuery.max().trainIds(trainIdList).build()))
                    .stream().collect(Collectors.groupingBy(PracticeRecordBO::getPracticeUserId)));
        }
        Map<Long, List<ExaminationRecordBO>> examinationMap = new HashMap<>();
        if (isWithExaminationRecord) {
            examinationMap.putAll(ExaminationRecordConverter.fromPO(
                            examinationRecordDao.listExaminationRecord(
                                    ExaminationRecordQuery.max().trainIds(trainIdList).build()))
                    .stream().collect(Collectors.groupingBy(ExaminationRecordBO::getExamineeUserId)));
        }

        Map<Long, Map<Long, List<TrainUserBO>>> userGroupByTrainMap = new HashMap<>();
        Map<Long, List<TrainUserBO>> trainUserMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(trainUserBOS)) {
            trainUserBOS.forEach(e -> {
                if (e.getFromGroupFlag()) {
                    if (isWithUser) {
                        List<TrainUserBO> trainUserBOS2 = trainUserMap.computeIfAbsent(e.getTrainId(), (k) -> new ArrayList<>());
                        trainUserBOS2.add(e);
                    }
                    Map<Long, List<TrainUserBO>> longListMap = userGroupByTrainMap.computeIfAbsent(e.getTrainId(), (k) -> new HashMap<>());
                    List<TrainUserBO> trainUserBOS1 = longListMap.computeIfAbsent(e.getUserGroupId(), (k) -> new ArrayList<>());
                    trainUserBOS1.add(e);
                }
                if (!CollectionUtils.isEmpty(learnMap) && learnMap.containsKey(e.getUserId())) {
                    e.setLearnRecordBOS(learnMap.get(e.getUserId()));
                }
                if (!CollectionUtils.isEmpty(practiceMap) && practiceMap.containsKey(e.getUserId())) {
                    e.setPracticeRecordBOS(practiceMap.get(e.getUserId()));
                }
                if (!CollectionUtils.isEmpty(examinationMap) && examinationMap.containsKey(e.getUserId())) {
                    e.setExaminationRecordBOS(examinationMap.get(e.getUserId()));
                }
            });
        }

        Map<Long, List<TrainUserGroupBO>> trainUserGroupMap = new HashMap<>();
        if (isWithUserGroup) {
            trainUserGroupMap.putAll(TrainUserGroupConverter.fromPO(
                            trainUserGroupDao.listTrainUserGroupById(trainIdList))
                    .stream().collect(Collectors.groupingBy(TrainUserGroupBO::getTrainId)));
            if (!CollectionUtils.isEmpty(trainUserGroupMap)) {
                trainUserGroupMap.forEach((key, value) -> {
                    Map<Long, List<TrainUserBO>> longListMap = userGroupByTrainMap.get(key);
                    value.forEach(e -> {
                        e.setTrainUserBOS(longListMap.get(e.getUserGroupId()));
                    });
                });
            }
        }
        Map<Long, List<TrainDocumentRelBO>> trainDocumentMap = new HashMap<>(TrainDocumentRelConverter.fromPO(
                        trainDocumentRelDao.listTrainDocumentRelById(trainIdList))
                .stream().collect(Collectors.groupingBy(TrainDocumentRelBO::getTrainId)));
        userGroupByTrainMap.clear();
        trainBOList.forEach(t -> {
            if (!CollectionUtils.isEmpty(trainUserMap) && trainUserMap.containsKey(t.getTrainId())) {
                t.setTrainUserBOS(trainUserMap.get(t.getTrainId()));
            }
            if (!CollectionUtils.isEmpty(trainUserGroupMap) && trainUserGroupMap.containsKey(t.getTrainId())) {
                t.setTrainUserGroupBOS(trainUserGroupMap.get(t.getTrainId()));
            }
            if (!CollectionUtils.isEmpty(trainDocumentMap) && trainDocumentMap.containsKey(t.getTrainId())) {
                t.setTrainDocumentRelBOS(trainDocumentMap.get(t.getTrainId()));
            }
        });
    }

    @Override
    public int countTrain(TrainQuery query) {
        return trainDao.countTrain(query);
    }

    /**
     * 获取发放团队下的人员
     */
    private Map<Long, List<TrainUserBO>> getUser(Map<Long, List<TrainUserGroupBO>> trainUserGroupMap) {
        List<Long> userGroupIds = new ArrayList<>();
        trainUserGroupMap.forEach((key, value) -> {
            //获取所有的groupID
            userGroupIds.addAll(value.stream().map(v -> v.getUserGroupId()).collect(Collectors.toSet()));
        });
        //查找团队下的成员id
        List<Long> userIds = ResultUtils.get(userClient.listUserByUserGroup(ListUserGroupByIdsRequest.builder().groupIds(userGroupIds).build())).stream().map(UserDTO::getUserId).collect(Collectors.toList());
        Map<Long, List<TrainUserBO>> collect = TrainUserConverter.fromPO(trainUserDao.listTrainUser(TrainUserQuery.max().userIdS(userIds).build())).stream().collect(Collectors.groupingBy(TrainUserBO::getTrainId));
        for (Map.Entry<Long, List<TrainUserGroupBO>> entry : trainUserGroupMap.entrySet()) {
            for (TrainUserGroupBO t : entry.getValue()) {
                if (collect.containsKey(t.getTrainId())) {
                    List<TrainUserBO> trainUserBOS = collect.get(t.getTrainId());
                    Map<Long, List<TrainUserBO>> collect1 = trainUserBOS.stream().collect(Collectors.groupingBy(TrainUserBO::getUserGroupId));
                    t.setTrainUserBOS(collect1.get(t.getUserGroupId()));
                }
            }
        }
        trainUserGroupMap.forEach((key, value) -> {
            value = value.stream()
                    .peek(v -> {
                        if (collect.containsKey(v.getTrainId())) {
                            List<TrainUserBO> trainUserBOS = collect.get(v.getTrainId());
                            Map<Long, List<TrainUserBO>> collect1 = trainUserBOS.stream().collect(Collectors.groupingBy(TrainUserBO::getUserGroupId));
                            v.setTrainUserBOS(collect1.get(v.getUserGroupId()));
                        }
                    })
                    .collect(Collectors.toList());
        });

        return collect;
    }

    private Map<Long, List<TrainUserBO>> getReleaseUser(Map<Long, List<TrainUserBO>> userByGroupMap, Map<Long, List<TrainUserBO>> userMap) {
        List<TrainUserBO> userByGroup = new ArrayList<>();
        userByGroupMap.forEach((key, value) -> {
            userByGroup.addAll(value);
        });
        List<TrainUserBO> user = new ArrayList<>();
        userMap.forEach((key, value) -> {
            user.addAll(value);
        });
        return user.stream().filter(item -> !userByGroup.contains(item)).collect(Collectors.groupingBy(TrainUserBO::getUserId));
    }
}
